package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class CartInfoServiceImpl implements CartInfoService {
    //商品勾选状态 1选中 0未选中
    private static final Integer IS_CHECKED = 1;
    private static final Integer NO_CHECKED = 0;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private CartInfoMapper cartInfoMapper;

    @Resource
    private ProductFeignClient productFeignClient;

    //添加商品到购物车
    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        String userId = getUserId();
        //查询缓存，判断该商品是否已经加入购物车
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheKey = skuId.toString();
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheCarInfo,cacheKey);
        if (cartInfo != null){
            //修改商品数量 重新放入缓存和数据库中
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            cartInfo.setIsChecked(IS_CHECKED);
            CompletableFuture.runAsync(() -> {
                cartInfoMapper.update(cartInfo,new QueryWrapper<CartInfo>()
                        .eq("sku_id",skuId)
                        .eq("user_id",cartInfo.getUserId()));
            });
            redisTemplate.opsForHash().put(cacheCarInfo,cacheKey,cartInfo);
            //return cartInfo;
        } else {
            //添加新的商品信息到缓存和数据库中
            CartInfo newCartInfo = new CartInfo();
            newCartInfo.setUserId(userId);
            newCartInfo.setSkuId(skuId);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            newCartInfo.setCartPrice(skuInfo.getPrice());
            newCartInfo.setSkuNum(skuNum);
            newCartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            newCartInfo.setSkuName(skuInfo.getSkuName());
            newCartInfo.setSkuPrice(productFeignClient.getPrice(skuId));
            CompletableFuture.runAsync(() -> {
                cartInfoMapper.insert(newCartInfo);
            });
            redisTemplate.opsForHash().put(cacheCarInfo,cacheKey,newCartInfo);
            //return newCartInfo;
        }
    }

    //获取用户Id
    private String getUserId() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)){
            userId = AuthContextHolder.getUserTempId(request);
        }
        return userId;
    }

    //查询购物车商品
    @Override
    public CartInfo getCartInfo(Long skuId) {
        String userId = getUserId();
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheKey = skuId.toString();
        return (CartInfo) redisTemplate.opsForHash().get(cacheCarInfo,cacheKey);
    }

    //查询当前用户购物车所有商品
    //考虑两个用户 一个真实用户 一个临时用户
    //临时用户
    //真实用户
    //真实用户+临时用户
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //有真实用户
        if (!StringUtils.isEmpty(userId)){
            if (!StringUtils.isEmpty(userTempId)){
                //有真实用户 有临时用户
                return mergeCartInfoList(userId,userTempId);
            } else {
                //有真实用户 无临时用户 查询缓存获取数据
                return getCartInfoList(userId);
            }
        } else {
            //无真实用户
            if (!StringUtils.isEmpty(userTempId)){
                //无真实用户 有临时用户
                return getCartInfoList(userTempId);
            }
            //无真实用户 无临时用户
        }
        return null;
    }

    // 更新选中状态
    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //从缓存中获取
        String userId = getUserId();
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheKey = skuId.toString();
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheCarInfo, cacheKey);
        cartInfo.setIsChecked(isChecked);
        //放回缓存中 异步更新数据库
        redisTemplate.opsForHash().put(cacheCarInfo,cacheKey,cartInfo);
        CompletableFuture.runAsync(() -> {
            cartInfoMapper.update(cartInfo,new QueryWrapper<CartInfo>()
                    .eq("user_id",userId)
                    .eq("sku_id",skuId));
        });
    }

    //删除购物车
    @Override
    public void deleteCart(Long skuId) {
        String userId = getUserId();
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheKey = skuId.toString();
        redisTemplate.opsForHash().delete(cacheCarInfo,cacheKey);
        CompletableFuture.runAsync(() -> {
            cartInfoMapper.delete(new QueryWrapper<CartInfo>()
                    .eq("user_id",userId)
                    .eq("sku_id",skuId));
        });
    }

    //查询选中的购物车集合
    @Override
    public List<CartInfo> cartListIsChecked(String userId) {
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheCarInfo);
        return cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() > 0).collect(Collectors.toList());
    }

    //有真实用户有临时用户的情况下合并购物车集合
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //分别获取真实用户购物车集合和临时用户购物车集合
        List<CartInfo> cartInfoList = getCartInfoList(userId);
        List<CartInfo> cartInfoListTemp = getCartInfoList(userTempId);
        String cacheCarInfoTemp = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //有真实用户购物车集合
        if (!CollectionUtils.isEmpty(cartInfoList)){
            if (!CollectionUtils.isEmpty(cartInfoListTemp)){
                //有真实用户购物车集合 有临时用户购物车集合
                //stream流转换成map集合 k:skuId v:cartInfo
                Map<Long, CartInfo> m = cartInfoList.stream()
                        .collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));

                cartInfoListTemp.stream().forEach(cartInfoTemp -> {
                    CartInfo cartInfo = m.get(cartInfoTemp.getSkuId());
                    if (cartInfo != null){
                        cartInfo.setSkuNum(cartInfo.getSkuNum() + cartInfoTemp.getSkuNum());
                        cartInfo.setIsChecked(IS_CHECKED);
                        //更新redis 异步更新数据库
                        redisTemplate.opsForHash().put(cacheCarInfo,cartInfo.getSkuId().toString(),cartInfo);
                        //异步更新数据库
                        CompletableFuture.runAsync(() -> {
                            cartInfoMapper.update(cartInfo,new QueryWrapper<CartInfo>()
                                    .eq("user_id",userId)
                                    .eq("sku_id",cartInfo.getSkuId()));
                            cartInfoMapper.delete(new QueryWrapper<CartInfo>()
                                    .eq("user_id",userTempId)
                                    .eq("sku_id",cartInfo.getSkuId()));
                        });
                    } else {
                        //redis缓存中添加没有的数据
                        redisTemplate.opsForHash().put(cacheCarInfo,cartInfoTemp.getSkuId().toString(),cartInfoTemp);
                        //异步 数据库中添加没有的数据
                        CompletableFuture.runAsync(() -> {
                            CartInfo info = new CartInfo();
                            info.setUserId(userId);
                            cartInfoMapper.update(info,new QueryWrapper<CartInfo>()
                                    .eq("user_id",userTempId)
                                    .eq("sku_id",cartInfoTemp.getSkuId()));
                        });
                        //真实用户购物车集合中没有的购物车添加
                        m.put(cartInfoTemp.getSkuId(),cartInfoTemp);
                    }
                });
                //删除缓存中临时购物车集合数据
                redisTemplate.delete(cacheCarInfoTemp);
                return new ArrayList(m.values());
            } else {
                //有真实用户购物车集合 无临时用户购物车集合
                return cartInfoList;
            }
        } else {
            //无真实用户购物车集合
            if (!CollectionUtils.isEmpty(cartInfoListTemp)){
                //无真实用户购物车集合 有临时用户购物车集合
                Map<String, CartInfo> collect = cartInfoListTemp.stream().map(cartInfo -> {
                    cartInfo.setUserId(userId);
                    return cartInfo;
                }).collect(Collectors.toMap(CartInfo -> CartInfo.getSkuId().toString(), cartInfo -> cartInfo));
                //异步 修改数据库
                CompletableFuture.runAsync(() -> {
                    CartInfo cartInfo = new CartInfo();
                    cartInfo.setUserId(userId);
                    cartInfoMapper.update(cartInfo,new QueryWrapper<CartInfo>()
                            .eq("user_id",userTempId));
                });
                //添加真实用户缓存
                redisTemplate.opsForHash().putAll(cacheCarInfo,collect);
                //删除redis临时用户购物车集合的缓存
                redisTemplate.delete(cacheCarInfoTemp);
                return cartInfoListTemp;
            }
                //无真实用户购物车集合 无临时用户购物车集合
        }
        return null;
    }

    //查询缓存获取购物车集合
    private List<CartInfo> getCartInfoList(String id) {
        String cacheCarInfo = RedisConst.USER_KEY_PREFIX + id + RedisConst.USER_CART_KEY_SUFFIX;
        //更新实时价格
        List<CartInfo> list = redisTemplate.opsForHash().values(cacheCarInfo);
        for (CartInfo cartInfo : list) {
            cartInfo.setSkuPrice(productFeignClient.getPrice(cartInfo.getSkuId()));
        }
        //数据库加入时间字段并排序
        /*List<CartInfo> sorted = list.stream().sorted((o1, o2) -> o1.getUpdateTime().compareTo(o2.getUpdateTime()))
                .collect(Collectors.toList());*/

        return list;
    }
}
